﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JStore.Core.Commands;
using JStore.Core.Dtos;
using JStore.Core.Entities;
using JStore.Core.Enums;
using JStore.Data.Daos;
using SpeadFrm.MvcPager;
using SpeadFrm.Utility;

namespace JStore.Tasks
{
    /// <summary>
    ///
    /// </summary>
    public class UserInfoTask
    {
        /// <summary>
        /// 接点奖最大层数为2
        /// </summary> 
        private const int MaxParentJdLayer = 2;

        /// <summary>
        /// 复消比率
        /// </summary>
        private const decimal RepeatRate = 0.10M;

        /// <summary>
        /// 培育奖层数
        /// </summary>
        private const int MaxFosterMoneyLayer = 2;

        private readonly UserInfoDao _userInfoDao = new UserInfoDao();
        private readonly UserTypeDao _userTypeDao = new UserTypeDao();
        private readonly CardTypeDao _cardTypeDao = new CardTypeDao();
        private readonly UserPasswordDao _userPasswordDao = new UserPasswordDao();
        private readonly MoneyLogDao _moneyLogDao = new MoneyLogDao();
        private readonly UserTypeJdRateConfigDao _userTypeJdRateConfigDao = new UserTypeJdRateConfigDao();
        private readonly UserNameBuilderDao _userNameBuilderDao = new UserNameBuilderDao();

        private readonly SysMsgTask _sysMsgTask = new SysMsgTask();
        private readonly CompanyMoneyLogTask _companyMoneyLogTask = new CompanyMoneyLogTask();

        public bool CanTj(string userName)
        {
            return _userInfoDao.ExistsUser(userName);
        }

        public bool CanJd(string userName, out string errMsg)
        {
            errMsg = string.Empty;

            var userInfo = _userInfoDao.GetByUserName(userName);
            if (userInfo == null)
            {
                errMsg = "批发商不存在";
                return false;
            }

            var userType = _userTypeDao.GetById(userInfo.UserTypeId);
            var jdCount = _userInfoDao.GetJdCount(userInfo.UserName);
            var maxJdCountPreLayer = userInfo.IsArea ? userType.AreaJdCountPreLayer : userType.JdCountPreLayer;

            var canJd = jdCount < maxJdCountPreLayer;
            if (!canJd)
                errMsg = "对不起，批发商下层市场已满";
            return canJd;
        }

        public List<int> GetJdSortList(string userName)
        {
            var list = new List<int>();
            var userInfo = _userInfoDao.GetByUserName(userName);
            if (userInfo == null) return list;

            var userType = _userTypeDao.GetById(userInfo.UserTypeId);
            var jdCount = _userInfoDao.GetJdCount(userInfo.UserName);
            var maxJdCountPreLayer = userInfo.IsArea ? userType.AreaJdCountPreLayer : userType.JdCountPreLayer;

            for (var i = jdCount + 1; i <= maxJdCountPreLayer; i++)
                list.Add(i);
            return list;
        }

        public bool Register(RegisterCmd cmd, string operUserName, out string errMsg, out int outUserId)
        {
            errMsg = string.Empty;
            outUserId = 0;

            #region 参数校验

            if (string.IsNullOrEmpty(cmd.Password))
            {
                errMsg = "登录密码不能为空";
                return false;
            }

            if (string.IsNullOrEmpty(cmd.Name))
            {
                errMsg = "真实姓名不能为空";
                return false;
            }

            if (string.IsNullOrEmpty(cmd.JdUserName))
            {
                errMsg = "批发商不能为空";
                return false;
            }

            if (string.IsNullOrEmpty(cmd.TjUserName))
            {
                errMsg = "零售商不能为空";
                return false;
            }

            if (cmd.JoinMoney <= 0)
            {
                errMsg = "消费金额必须大于0";
                return false;
            }

            if (cmd.RealMoney <= 0)
            {
                errMsg = "实消金额必须大于0";
                return false;
            }

            // 消费种类校验
            var cardType = _cardTypeDao.GetById(cmd.CardType);
            if (cardType == null)
            {
                errMsg = "不存在此消费种类";
                return false;
            }

            // 零售商校验
            if (!CanTj(cmd.TjUserName))
            {
                errMsg = "零售商不存在";
                return false;
            }

            // 批发商校验
            if (!CanJd(cmd.JdUserName, out errMsg))
                return false;

            // 顺序号校验
            if (!GetJdSortList(cmd.JdUserName).Contains(cmd.JdSort))
            {
                errMsg = "对不起，顺序号已被使用";
                return false;
            }

            #endregion

            var tjUser = _userInfoDao.GetByUserName(cmd.TjUserName);
            var jdUser = _userInfoDao.GetByUserName(cmd.JdUserName);

            var balanceMoney = cardType.BalanceRate * cmd.RealMoney;

            var userName = _userNameBuilderDao.Builder();
            // 添加UserPassword
            var userPassword = new UserPassword
                                   {
                                       CreateDate = DateTime.Now,
                                       IsLock = false,
                                       Password = CryptTools.HashPassword(cmd.Password),
                                       RoleId = 2,
                                       UserName = userName
                                   };
            var userId = Convert.ToInt32(_userPasswordDao.Add(userPassword));

            var userInfo = new UserInfo
                               {
                                   Address = cmd.Address,
                                   AreaUserId = null,
                                   AreaUserName = string.Empty,
                                   CardClass = cmd.CardClass,
                                   CardType = cmd.CardType,
                                   IsArea = false,
                                   JdSort = cmd.JdSort,
                                   JdUserId = jdUser.UserId,
                                   JdUserName = jdUser.UserName,
                                   JoinMoney = cmd.JoinMoney,
                                   Mobile = cmd.Mobile,
                                   Name = cmd.Name,
                                   Phone = cmd.Phone,
                                   RealMoney = cmd.RealMoney,
                                   TjUserId = tjUser.UserId,
                                   TjUserName = tjUser.UserName,
                                   UserId = userId,
                                   UserName = userName,
                                   UserTypeId = cardType.UserTypeId,
                                   CreateDate = DateTime.Now,
                               };
            _userInfoDao.Add(userInfo);

            // 添加收入日志
            var operUserPassword = _userPasswordDao.GetByUserName(operUserName);
            _companyMoneyLogTask.CreateRegLog(userInfo.UserId, userInfo.UserName, (decimal)userInfo.RealMoney,
                                              operUserPassword.UserId, operUserPassword.UserName);

            // 零售奖（推荐）结算
            RiseTjMoney(userInfo, balanceMoney);

            // 批发奖（接点）结算
            RiseJdMoney(userInfo, balanceMoney);

            // 管理奖结算
            RiseManageMoney(userInfo, balanceMoney);

            // 培育奖结算
            RiseFosterMoney(userInfo, balanceMoney);

            // 区代升级校验
            CheckForArea(userInfo);

            outUserId = userId;
            return true;
        }

        private string BuildUserName()
        {
            return _userNameBuilderDao.Builder();
        }

        /// <summary>
        /// 区代校验
        /// </summary>
        /// <param name="userInfo"></param>
        private void CheckForArea(UserInfo userInfo)
        {
            var parentJdWithoutAreaList = _userInfoDao.GetParentJdListWithArea(userInfo.UserName);
            if (parentJdWithoutAreaList == null || parentJdWithoutAreaList.Count == 0)
                return;
            var topUser = parentJdWithoutAreaList.Last();
            var topUserJdTreeCout = _userInfoDao.GetJdTreeCount(topUser.UserName, 40);

            var layerIndex = 0;
            foreach (var info in parentJdWithoutAreaList)
            {
                layerIndex += 1;
                if (_userInfoDao.GetTjCount(info.UserName) < 3) continue;
                if (layerIndex <= 2)
                {
                    if (_userInfoDao.GetJdTreeCount(info.UserName, 2) == 12)
                        CreateAreaUser(info);
                }
                else
                {
                    if (topUserJdTreeCout > 40 && _userInfoDao.GetJdTreeCount(info.UserName, 40) >= 40)
                        CreateAreaUser(info);
                }
            }
        }

        private void CreateAreaUser(UserInfo userInfo)
        {
            var userPassword = _userPasswordDao.GetByUserName(userInfo.UserName);
            var userName = string.Format("区代{0}", userPassword.UserName);
            var areaUserPassword = new UserPassword
                                      {
                                          CreateDate = DateTime.Now,
                                          IsLock = false,
                                          Password = userPassword.Password,
                                          RoleId = userPassword.RoleId,
                                          UserName = userName,
                                      };
            var userId = Convert.ToInt32(_userPasswordDao.Add(areaUserPassword));

            var areaUserInfo = new UserInfo
                               {
                                   Address = userInfo.Address,
                                   AreaUserId = null,
                                   AreaUserName = string.Empty,
                                   CardClass = userInfo.CardClass,
                                   CardType = userInfo.CardType,
                                   IsArea = true,
                                   JdSort = null,
                                   JdUserId = null,
                                   JdUserName = string.Empty,
                                   JoinMoney = userInfo.JoinMoney,
                                   Mobile = userInfo.Mobile,
                                   Name = userInfo.Name,
                                   Phone = userInfo.Phone,
                                   RealMoney = userInfo.RealMoney,
                                   TjUserId = null,
                                   TjUserName = string.Empty,
                                   UserId = userId,
                                   UserName = userName,
                                   UserTypeId = userInfo.UserTypeId,
                                   CreateDate = DateTime.Now,
                               };
            _userInfoDao.Add(areaUserInfo);

            RiseAreaTj(userInfo, areaUserInfo);

            var title = "恭喜您升级为区级代理商！";
            var content = new StringBuilder();
            content.Append("<p>恭喜您，您已升级为【<label class='red'>区代</label>】，您对应的区代账号为<label class='red'>"
                           + areaUserInfo.UserName + "</label>，登录密码与您此账号一致，请及时修改密码</p>");
            _sysMsgTask.CreateMsg(userInfo.UserId, userInfo.UserName, title, content.ToString());
        }

        private void RiseAreaTj(UserInfo userInfo, UserInfo areaUserInfo)
        {
            var tjList = _userInfoDao.GetTjTreeList(userInfo.UserName, 1);
            if (tjList.Count <= 3) return;

            var riseList = tjList.OrderBy(c => c.CreateDate).Skip(3);
            var areaUserType = _userTypeDao.GetById(areaUserInfo.UserTypeId);

            var list = (from info in riseList
                        let cardType = _cardTypeDao.GetById(info.CardType)
                        let balanceMoney = cardType.BalanceRate * (decimal)info.RealMoney
                        select new MoneyLog
                                   {
                                       BalanceMoney = balanceMoney,
                                       CreateDate = DateTime.Now,
                                       IsSend = false,
                                       OtherRate = areaUserType.AreaRepeatRate,
                                       Rate = areaUserType.AreaTjRate,
                                       TotalMoney = balanceMoney * areaUserType.AreaTjRate,
                                       RealMoney = balanceMoney * areaUserType.AreaTjRate * (1 - areaUserType.AreaRepeatRate),
                                       SourceUserId = info.UserId,
                                       SourceUserName = info.UserName,
                                       UserId = areaUserInfo.UserId,
                                       UserName = areaUserInfo.UserName,
                                       MoneyType = MoneyType.TjMoney,
                                   }).ToList();
            foreach (var moneyLog in list)
            {
                _moneyLogDao.Add(moneyLog);
            }

            _userInfoDao.SetTjUser(areaUserInfo.UserId, areaUserInfo.UserName, riseList.Select(c => c.UserId).ToList());
        }

        /// <summary>
        /// 培育奖结算
        /// </summary>
        private void RiseFosterMoney(UserInfo userInfo, decimal balanceMoney)
        {
            // 获取接点关系的父级中的区代
            var parentJdAreaUserInfo = _userInfoDao.GetParentJdArea(userInfo.UserName);

            // 没有区代则不结算
            if (parentJdAreaUserInfo == null)
                return;

            // 获取区代的可拿培育奖的推荐父级列表
            var parentTjList = _userInfoDao.GetParentTjList(parentJdAreaUserInfo.UserName, MaxFosterMoneyLayer);

            // 区代对应的普通会员账号
            var customeUserInfo = _userInfoDao.GetByAreaUserId(parentJdAreaUserInfo.UserId);
            foreach (var tjUser in parentTjList)
            {
                // 如果区代的推荐人不是区代，则不结算
                if (!tjUser.IsArea) continue;
                // 如果【区代对应的普通会员账号】不在【区代的推荐人】的接点团队中，则不结算
                if (CheckJdHas(tjUser.UserId, customeUserInfo.UserId) <= 0) continue;

                var tjUserType = _userTypeDao.GetById(tjUser.UserTypeId);
                var moneyLog = new MoneyLog
                                   {
                                       BalanceMoney = balanceMoney,
                                       CreateDate = DateTime.Now,
                                       MoneyType = MoneyType.FosterMoney,
                                       OtherRate = RepeatRate,
                                       Rate = tjUserType.AreaFosterRate,
                                       RealMoney = balanceMoney * tjUserType.AreaFosterRate * (1 - RepeatRate),
                                       SourceUserId = userInfo.UserId,
                                       SourceUserName = userInfo.UserName,
                                       TotalMoney = balanceMoney * tjUserType.AreaFosterRate,
                                       UserId = tjUser.UserId,
                                       UserName = tjUser.UserName,
                                       IsSend = false,
                                   };
                _moneyLogDao.Add(moneyLog);
                customeUserInfo = _userInfoDao.GetByAreaUserId(tjUser.UserId);
            }
        }

        /// <summary>
        /// 管理奖结算
        /// </summary>
        /// <param name="userInfo"></param>
        /// <param name="balanceMoney"></param>
        private void RiseManageMoney(UserInfo userInfo, decimal balanceMoney)
        {
            // 获取接点关系的父级中的区代
            var parentJdAreaUserInfo = _userInfoDao.GetParentJdArea(userInfo.UserName);

            // 没有区代则不结算
            if (parentJdAreaUserInfo == null)
                return;

            // 区代存在但没超过2层，则不结算
            if (_userInfoDao.GetParentJdList(userInfo.UserName, MaxParentJdLayer).Select(c => c.UserId).Contains(parentJdAreaUserInfo.UserId))
                return;

            var parentAreaUserType = _userTypeDao.GetById(parentJdAreaUserInfo.UserTypeId);
            var moneyLog = new MoneyLog
                               {
                                   BalanceMoney = balanceMoney,
                                   CreateDate = DateTime.Now,
                                   Id = 1,
                                   MoneyType = MoneyType.ManageMoney,
                                   OtherRate = RepeatRate,
                                   Rate = parentAreaUserType.AreaManageRate,
                                   TotalMoney = balanceMoney * parentAreaUserType.AreaManageRate,
                                   RealMoney = balanceMoney * parentAreaUserType.AreaManageRate * (1 - RepeatRate),
                                   SourceUserId = userInfo.UserId,
                                   SourceUserName = userInfo.UserName,
                                   UserId = parentJdAreaUserInfo.UserId,
                                   UserName = parentJdAreaUserInfo.UserName,
                                   IsSend = false,
                               };
            _moneyLogDao.Add(moneyLog);
        }

        /// <summary>
        /// 批发奖（接点）结算
        /// </summary>
        /// <param name="userInfo"></param>
        /// <param name="balanceMoney"></param>
        private void RiseJdMoney(UserInfo userInfo, decimal balanceMoney)
        {
            // 获取父级接点人列表
            var parentJdList = _userInfoDao.GetParentJdList(userInfo.UserName, MaxParentJdLayer);
            var rateConfigList = _userTypeJdRateConfigDao.GetAll();
            for (int i = 0; i < parentJdList.Count; i++)
            {
                var layerIndex = i + 1;
                var jdUser = parentJdList[i];
                var rateConfig = rateConfigList.FirstOrDefault(c => c.LayerIndex == layerIndex && c.UserTypeId == jdUser.UserTypeId);
                if (rateConfig == null) throw new Exception("配置异常【批发奖配置】");

                var jdRate = jdUser.IsArea ? rateConfig.AreaRate : rateConfig.Rate;
                var moneyLog = new MoneyLog
                                   {
                                       BalanceMoney = balanceMoney,
                                       CreateDate = DateTime.Now,
                                       MoneyType = MoneyType.JdMoney,
                                       OtherRate = RepeatRate,
                                       Rate = jdRate,
                                       TotalMoney = balanceMoney * jdRate,
                                       RealMoney = balanceMoney * jdRate * (1 - RepeatRate),
                                       SourceUserId = userInfo.UserId,
                                       SourceUserName = userInfo.UserName,
                                       UserId = jdUser.UserId,
                                       UserName = jdUser.UserName,
                                       IsSend = false,
                                   };
                _moneyLogDao.Add(moneyLog);
            }

        }

        /// <summary>
        /// 零售奖（推荐）结算
        /// </summary> 
        private void RiseTjMoney(UserInfo userInfo, decimal balanceMoney)
        {
            var tjUser = _userInfoDao.GetByUserName(userInfo.TjUserName);
            var tjUserType = _userTypeDao.GetById(tjUser.UserTypeId);

            // 得到推荐奖结算比率
            var tjRate = tjUser.IsArea ? tjUserType.AreaTjRate : tjUserType.TjRate;

            var moneyLog = new MoneyLog
                               {
                                   BalanceMoney = balanceMoney,
                                   CreateDate = DateTime.Now,
                                   MoneyType = MoneyType.TjMoney,
                                   Rate = tjRate,
                                   TotalMoney = tjRate * balanceMoney,
                                   OtherRate = RepeatRate,
                                   RealMoney = tjRate * balanceMoney * (1 - RepeatRate),
                                   SourceUserId = userInfo.UserId,
                                   SourceUserName = userInfo.UserName,
                                   UserId = tjUser.UserId,
                                   UserName = tjUser.UserName,
                                   IsSend = false,
                               };
            _moneyLogDao.Add(moneyLog);
        }

        /// <summary>
        /// 获取接点的父级列表
        /// </summary>
        public List<UserInfo> GetParentJdList(string userName, int layer)
        {
            return _userInfoDao.GetParentJdList(userName, layer);
        }

        /// <summary>
        /// 获取推荐关系的父级列表
        /// </summary>
        public List<UserInfo> GetParentTjList(string userName, int layer)
        {
            return _userInfoDao.GetParentTjList(userName, layer);
        }

        /// <summary>
        /// 获取接点的父级中的区代
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public UserInfo GetParentJdArea(string userName)
        {
            return _userInfoDao.GetParentJdArea(userName);
        }

        public List<UserInfo> GetJdTreeList(string userName, int layer)
        {
            return _userInfoDao.GetJdTreeList(userName, layer);
        }

        public List<UserInfo> GetParentJdListWithArea(string userName)
        {
            return _userInfoDao.GetParentJdListWithArea(userName);
        }

        public int GetTjCount(string userName)
        {
            return _userInfoDao.GetTjCount(userName);
        }

        /// <summary>
        /// 得到UserId的会员在ParentUserId下的接点关系中的层级
        /// </summary> 
        public int CheckJdHas(int parentUserId, int userId)
        {
            return _userInfoDao.CheckJdHas(parentUserId, userId);
        }

        public UserInfo GetByUserName(string userName)
        {
            return _userInfoDao.GetByUserName(userName);
        }

        public PagedList<UserInfoDto> GetPagedList(string userName, string jdUserName, string tjUserName, int? userTypeId, string areaUserName, bool? isArea, int pageIndex, int pageSize)
        {
            return _userInfoDao.GetPagedList(userName, jdUserName, tjUserName, userTypeId, areaUserName, isArea,
                                             pageIndex, pageSize);
        }

        public List<UserInfo> GetTjTreeList(string userName, int layer)
        {
            return _userInfoDao.GetTjTreeList(userName, layer);
        }

        public void Update(UserInfo userInfo)
        {
            _userInfoDao.Update(userInfo);
        }

        public UserInfo GetByUserId(int userId)
        {
            return _userInfoDao.GetByUserId(userId);
        }

        public bool CanUpdate(string userName, out string errMsg)
        {
            errMsg = string.Empty;
            var userInfo = _userInfoDao.GetByUserName(userName);
            if (userInfo == null)
            {
                errMsg = "会员账号不存在";
                return false;
            }

            if (userInfo.CardClass == CardClass.Store && userInfo.UserTypeId >= 2)
            {
                errMsg = "您已经是金卡会员";
                return false;
            }

            if (userInfo.UserTypeId >= 5)
            {
                errMsg = "您已经是董事金钻会员，无需升级";
                return false;
            }

            return true;
        }

        public bool Upgrade(string userName, int userTypeId, decimal realMoney, string operUserName, out string errMsg)
        {
            errMsg = string.Empty;

            var userType = _userTypeDao.GetById(userTypeId);
            if (userType == null)
            {
                errMsg = "会员类型不存在";
                return false;
            }

            if (!CanUpdate(userName, out errMsg))
                return false;

            var userInfo = _userInfoDao.GetByUserName(userName);
            if (userTypeId <= userInfo.UserTypeId)
            {
                errMsg = "会员类型错误";
                return false;
            }

            var cardType = _cardTypeDao.Get(userTypeId, CardClass.Member);
            if (cardType == null)
            {
                errMsg = "会员类型错误";
                return false;
            }

            userInfo.UserTypeId = userTypeId;
            userInfo.JoinMoney = cardType.Price;
            userInfo.RealMoney += realMoney;
            _userInfoDao.Update(userInfo);

            // 添加收入日志
            var operUserPassword = _userPasswordDao.GetByUserName(operUserName);
            _companyMoneyLogTask.CreateUpgradeLog(userInfo.UserId, userInfo.UserName, realMoney, operUserPassword.UserId,
                                                  operUserPassword.UserName);

            var balanceMoney = cardType.BalanceRate * realMoney;

            // 零售奖（推荐）结算
            RiseTjMoney(userInfo, balanceMoney);

            // 批发奖（接点）结算
            RiseJdMoney(userInfo, balanceMoney);

            // 管理奖结算
            RiseManageMoney(userInfo, balanceMoney);

            // 培育奖结算
            RiseFosterMoney(userInfo, balanceMoney);

            return true;
        }
    }
}

